`include "defines.v"
module bru(
  input                 valid_i  ,
  input                 predictJump,
  input  [`OP_W-1:0]    mode     ,
  input  [`XLEN-1:0]    op1      ,
  input  [`XLEN-1:0]    op2      ,
  input  [`XLEN-1:0]    imm      ,
  input  [`VADDR_W-1:0] pc       ,
  output [`XLEN-1:0]    out      ,
  output                br_valid ,
  output [`VADDR_W-1:0] br_addr  
`ifdef PREDICT_PC
  ,
  input                 baq_bru_valid_i ,
  input  [`VADDR_W-1:0] baq_bru_dout_i  ,
  output                bru_baq_ready_o 
`endif
);

wire equ = op1 == op2;
wire lt  = $signed(op1) < $signed(op2);
wire ltu = op1 < op2;

wire  real_br_valid = (mode == `BRU_JAL  ) || (mode == `BRU_JALR ) ||
                      ((mode == `BRU_BEQ  ) &&  equ )||  
                      ((mode == `BRU_BNE  ) && ~equ )||  
                      ((mode == `BRU_BGE  ) && ~lt  )||  
                      ((mode == `BRU_BGEU ) && ~ltu )|| 
                      ((mode == `BRU_BLT  ) &&  lt  )|| 
                      ((mode == `BRU_BLTU ) &&  ltu ); 
// JAL   PC + imm          out = PC+4
// JALR (rs1 + imm ) & ~1  out = PC+4
// B     PC + imm 
assign out = pc+4;
wire [`VADDR_W-1:0] real_br_addr = (((mode == `BRU_JALR) ? op1 : pc) + imm ) & ~((mode == `BRU_JALR) ? `ADDR_W'd1 : `ADDR_W'd0);
`ifdef PREDICT_PC
wire pcMatch = (baq_bru_dout_i == real_br_addr) && baq_bru_valid_i;
`else
wire pcMatch = 1'b1;
`endif
//  pre real  pcMatch  flush  jumpPc
//   0   0      0/1      0      0
//   0   1      0/1      1    realJumpPC 计算出的PC
//   1   0      0/1      1    pc+4
//   1   1       0       1    realJumpPC 计算出的PC
//   1   1       1       0      0
assign br_valid = (~predictJump && real_br_valid) || 
                  (predictJump && ~real_br_valid) || 
                  (predictJump && real_br_valid && ~pcMatch)  ;
assign br_addr  = (~predictJump && real_br_valid)            ? real_br_addr :
                  (predictJump && ~real_br_valid)            ? out          :
                  (predictJump && real_br_valid && ~pcMatch) ? real_br_addr : `ZERO;
`ifdef PREDICT_PC
assign bru_baq_ready_o = predictJump && baq_bru_valid_i && valid_i;
`endif
endmodule 